home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr05
/
xnot12a.zip
/
ECHO.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-25
|
17KB
|
868 lines
#include "jam.h"
#include "stdlib.h"
/*
* Echo line reading and writing.
*
* Common routines for reading
* and writing characters in the echo line area
* of the display screen. Used by the entire
* known universe.
*/
#include "def.h"
#include "key.h"
#include "macro.h"
#include "kbd.h"
#define EchoColor /* CHIGH */ CTEXT /* for normal colored prompt stuff */
static void rn_(altmessage,(char *s));
static int rn_(getxtra, (LIST *lp1, LIST *lp2, int cpos, int wflag));
static int rn_(veread, (char *fp, char *buf, int nbuf, int flag, va_list *ap));
static VOID rn_(eformat, (char *fp, va_list *ap));
static VOID rn_(eputi, (int i, int r));
static VOID rn_(eputl, (long l, int r));
static VOID rn_(eputs, (char *s));
static VOID rn_(eputc, (char c));
static int rn_(complt, (int flags, char c, char *buf, int cpos, int size));
int epresf = FALSE; /* Stuff in echo line flag. */
BOOL eprompting = FALSE;
/* JAM - more strings localized to prevent duplicates
*/
BOOL ealtmsg = FALSE;
static char *amb = " [Ambiguous]";
static char *nomatch = " [No match]";
static char preload[NFILEN] = {0}; /* preloaded a prompt (JAM ) */
static char altmsg[2*NFILEN] = {0}; /* for interruptable prompt (JAM) */
static char refreshmsg[2*NFILEN] = {0};
static int refreshoffset = 0;
static BOOL collectPrompt = FALSE;
static int altoffset = 0;
/*
* Erase the echo line.
*/
VOID eerase()
{
if (ealtmsg)
{
altmsg[0] = '\0';
altoffset = 0;
}
else
{
ttcolor(EchoColor);
ttmove(nrow-1, 0);
tteeol();
ttflush(FALSE);
}
epresf = FALSE;
}
/*
* Ask "yes" or "no" question.
* Return ABORT if the user answers the question
* with the abort ("^G") character. Return FALSE
* for "no" and TRUE for "yes". No formatting
* services are available. No newline required.
*/
eyorn(sp)
char *sp; {
register int s;
int result;
if(inmacro)
return TRUE;
eprompting = TRUE;
ewprintf("%s? (y or n) ", sp);
for (;;) {
s = getkey(FALSE);
if (s == 'y' || s == 'Y')
{
result = TRUE;
break;
}
if (s == 'n' || s == 'N')
{
result = FALSE;
break;
}
if (s == CCHR('G'))
{
result = ctrlg(FFRAND, 1);
break;
}
if (!handleKchar(s))
{
result = ABORT;
break;
}
ttbeep();
ewprintf("Please answer y or n. %s? (y or n) ", sp);
}
eprompting = FALSE;
return(result);
}
/*
* Like eyorn, but for more important question. User must type either all of
* "yes" or "no", and the trainling newline.
*/
eyesno(sp)
char *sp;
{
register int s;
char buf[64];
if(inmacro)
return TRUE;
eprompting = TRUE;
s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
for (;;) {
if (s == ABORT)
break;
if (s != FALSE) {
if (macrodef) {
LINE *lp = maclcur;
maclcur = lp->l_bp;
maclcur->l_fp = lp->l_fp;
free((char *)lp);
}
if ((buf[0] == 'y' || buf[0] == 'Y')
&& (buf[1] == 'e' || buf[1] == 'E')
&& (buf[2] == 's' || buf[2] == 'S')
&& (buf[3] == '\0'))
{
s = TRUE;
break;
}
if ((buf[0] == 'n' || buf[0] == 'N')
&& (buf[1] == 'o' || buf[0] == 'O')
&& (buf[2] == '\0'))
{
s = FALSE;
break;
}
}
if (!handleKchar(s))
{
s = ABORT;
break;
}
ttbeep();
s = ereply("Please answer yes or no. %s? (yes or no) ",
buf, sizeof(buf), sp);
}
eprompting = FALSE;
return(s);
}
/*
* Write out a prompt, and read back a
* reply. The prompt is now written out with full "ewprintf"
* formatting, although the arguments are in a rather strange
* place. This is always a new message, there is no auto
* completion, and the return is echoed as such.
*/
int ereply(va_alist)
va_dcl
{
va_list pvar;
register char *fp, *buf;
register int nbuf;
register int i;
va_start(pvar);
fp = va_arg(pvar, char *);
buf = va_arg(pvar, char *);
nbuf = va_arg(pvar, int);
i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar);
va_end(pvar);
return i;
}
/*
* This is the general "read input from the
* echo line" routine. The basic idea is that the prompt
* string "prompt" is written to the echo line, and a one
* line reply is read back into the supplied "buf" (with
* maximum length "len"). The "flag" contains EFNEW (a
* new prompt), an EFFUNC (autocomplete), or EFCR (echo
* the carriage return as CR).
*/
/* VARARGS 0 */
int eread(va_alist)
va_dcl
{
va_list pvar;
char *fp, *buf;
int nbuf, flag, i;
va_start(pvar);
fp = va_arg(pvar, char *);
buf = va_arg(pvar, char *);
nbuf = va_arg(pvar, int);
flag = va_arg(pvar, int);
i = veread(fp, buf, nbuf, flag, &pvar);
va_end(pvar);
return i;
}
static int veread(fp, buf, nbuf, flag, ap)
char *fp;
char *buf;
int nbuf, flag;
va_list *ap;
{
register int cpos;
register int i;
register int c;
int refreshlength;
BOOL wasvis = IsCaretVis();
SetCaretVis(FALSE);
if(inmacro) {
bcopy(maclcur->l_text, buf, (size_t)maclcur->l_used);
buf[maclcur->l_used] = '\0';
maclcur = maclcur->l_fp;
return TRUE;
}
eprompting = TRUE;
cpos = 0;
if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
ttcolor(EchoColor);
ttmove(nrow-1, 0);
epresf = TRUE;
} else
eputc(' ');
/* eformat will prime refreshmsg buffer
*/
eformat(fp, ap);
refreshlength = strlen(refreshmsg);
/* dump pre-loaded partial response
*/
AddString(preload);
preload[0] = '\0';
tteeol();
ttflush(FALSE);
for (;;) {
if (wasvis)
SetCaretVis(TRUE);
c = getkey(FALSE);
SetCaretVis(FALSE);
if ((flag & EFFILE) && ((c == (int)' ')
|| (c == (int)(CCHR('I')))))
{
char dbuf[NFILEN];
register int i;
for (i = 0; i < cpos; i++)
dbuf[i] = buf[i];
dbuf[i] = '\0';
ExtendedFunction(function_name(diredfiles_));
AddString(dbuf);
AddKchar(' ');
continue;
}
if ((flag&EFAUTO) != 0 && (c == (int)' ' ||
c == (int)CCHR('I')))
{
cpos += complt(flag, (char)c, buf, cpos, nbuf);
continue;
}
c = handleKchar(c);
if (!c)
c = CCHR('G');
switch (c) {
case CCHR('Z'):
ttcolor(EchoColor);
ttmove(nrow-1, 0);
eerase();
eputs(refreshmsg);
break; /* refresh? ignore it*/
case CCHR('J'):
c = CCHR('M'); /* and continue */
case CCHR('M'): /* Return, done. */
if ((flag&EFFUNC) != 0) {
if ((i = complt(flag, (char)c, buf, cpos, nbuf)) == 0)
continue;
if (i > 0)
cpos += i;
}
buf[cpos] = '\0';
if ((flag&EFCR) != 0) {
ttputc(CCHR('M'));
ttflush(FALSE);
}
if(macrodef) {
LINE *lp;
if((lp = lalloc(cpos)) == NULL)
return FALSE;
lp->l_fp = maclcur->l_fp;
maclcur->l_fp = lp;
lp->l_bp = maclcur;
maclcur = lp;
bcopy(buf, lp->l_text, (size_t)cpos);
}
goto done;
case CCHR('G'): /* Bell, abort. */
eputc(CCHR('G'));
(VOID) ctrlg(FFRAND, 0);
ttflush(FALSE);
eprompting = FALSE;
return ABORT;
case KDELETE:
case CCHR('H'):
case CCHR('?'): /* Rubout, erase. */
if (cpos != 0) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
if (ISCTRL(buf[--cpos]) != FALSE) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
}
ttflush(FALSE);
}
break;
case CCHR('X'): /* C-X */
case CCHR('U'): /* C-U, kill line. */
while (cpos != 0) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
if (ISCTRL(buf[--cpos]) != FALSE) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
}
}
ttflush(FALSE);
break;
case CCHR('W'): /* C-W, kill to beginning of */
/* previous word */
/* back up to first word character or beginning */
while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
if (ISCTRL(buf[--cpos]) != FALSE) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
}
}
while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
if (ISCTRL(buf[--cpos]) != FALSE) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
}
}
ttflush(FALSE);
break;
case CCHR('\\'):
case CCHR('Q'): /* C-Q, quote next */
c = getkey(FALSE); /* and continue */
default: /* All the rest. */
if (cpos < nbuf-1) {
buf[cpos++] = (char) c;
eputc((char) c);
ttflush(FALSE);
}
}
memcpy(&refreshmsg[refreshlength], buf, cpos);
refreshmsg[refreshlength + cpos] = '\0';
}
done:
eprompting = FALSE;
return buf[0] != '\0';
}
/*
* do completion on a list of objects.
*/
static int complt(flags, c, buf, cpos, nbuf)
int flags;
char c;
register char *buf;
register int cpos;
int nbuf;
{
register LIST *lh, *lh2;
int i, nxtra;
int nhits, bxtra;
int wflag = FALSE;
int msglen, nshown;
char *msg;
#ifdef WINDOWED
int cursoron = IsCaretVis();
#endif
if ((flags&EFFUNC) != 0) {
buf[cpos] = '\0';
i = complete_function(buf, c);
if(i>0) {
eputs(&buf[cpos]);
ttflush(FALSE);
return i;
}
switch(i) {
case -3:
msg = amb; /* ambiguous */
break;
case -2:
i=0;
msg = nomatch;
break;
case -1:
case 0:
return i;
default:
msg = " [Internal error]";
break;
}
} else {
if ((flags&EFBUF) != 0)
lh = &(bheadp->b_list);
else
panic("broken complt call: flags");
if (c == ' ')
wflag = TRUE;
else if (c != '\t' && c != CCHR('M'))
panic("broken complt call: c");
nhits = 0;
nxtra = HUGEN;
while (lh != NULL) {
for (i=0; i<cpos; ++i) {
if (buf[i] != lh->l_name[i])
break;
}
if (i == cpos) {
if (nhits == 0)
lh2 = lh;
++nhits;
if (lh->l_name[i] == '\0') nxtra = -1;
else {
bxtra = getxtra(lh, lh2, cpos, wflag);
if (bxtra < nxtra) nxtra = bxtra;
lh2 = lh;
}
}
lh = lh->l_next;
}
if (nhits == 0)
msg = nomatch;
else if (nhits > 1 && nxtra == 0)
msg = amb;
else { /* Got a match, do it to it */
/*
* Being lazy - ought to check length, but all things
* autocompleted have known types/lengths.
*/
if (nxtra < 0 && nhits > 1 && c == ' ')
nxtra = 1;
for (i = 0; i < nxtra; ++i)
{
if (cpos >= nbuf)
{
#ifdef WINDOWED
WindowMessage("Echo line overflow!", FALSE);
#else
# ifdef SomeUnix
printf("Echo line overflow!\n"); /* gross */
# endif
ewprintf("Echo line overflow!"); /* gross */
#endif
cpos--;
buf[cpos] = '\0';
break;
}
buf[cpos] = lh2->l_name[cpos];
eputc(buf[cpos++]);
}
ttflush(FALSE);
if (nxtra < 0 && c != CCHR('M'))
return 0;
return nxtra;
}
}
/* Set up backspaces, etc., being mindful of echo line limit
*/
msglen = strlen(msg);
nshown = (ttcol + msglen + 2 > ncol) ?
ncol - ttcol - 2 : msglen;
#ifdef WINDOWED
SetCaretVis(FALSE);
ttflush(TRUE);
#endif
eputs(msg);
ttflush(TRUE);
sleep(1);
ttcol -= (i = nshown); /* update ttcol! */
while (i--) /* move back before msg */
ttputc('\b');
ttflush(FALSE); /* display to user */
i = nshown;
while (i--) /* blank out on next flush */
eputc(' ');
ttcol -= (i = nshown); /* update ttcol on BS's */
while (i--)
ttputc('\b'); /* update ttcol again! */
#ifdef WINDOWED
SetCaretVis(cursoron);
ttflush(TRUE);
#endif
return 0;
}
/*
* The "lp1" and "lp2" point to list structures. The
* "cpos" is a horizontal position in the name.
* Return the longest block of characters that can be
* autocompleted at this point. Sometimes the two
* symbols are the same, but this is normal.
*/
static int getxtra(lp1, lp2, cpos, wflag)
register LIST *lp1, *lp2;
int cpos;
register int wflag;
{
register int i;
i = cpos;
for (;;) {
if (lp1->l_name[i] != lp2->l_name[i]) break;
if (lp1->l_name[i] == '\0') break;
++i;
if (wflag && !ISWORD(lp1->l_name[i-1])) break;
}
return (i - cpos);
}
/*
* Special "printf" for the echo line.
* Each call to "ewprintf" starts a new line in the
* echo area, and ends with an erase to end of the
* echo line. The formatting is done by a call
* to the standard formatting routine.
*/
/*VARARGS 0 */
VOID ewprintf(va_alist)
va_dcl
{
va_list pvar;
register char *fp;
if (inmacro)
return;
va_start(pvar);
fp = va_arg(pvar, char *);
if (!ealtmsg)
{
ttcolor(EchoColor);
ttmove(nrow-1, 0);
}
eformat(fp, &pvar);
va_end(pvar);
if (ealtmsg)
{
altmessage(altmsg);
altoffset = 0;
}
else
{
tteeol();
ttflush(FALSE);
}
epresf = TRUE;
}
/*
* Printf style formatting. This is
* called by both "ewprintf" and "ereply" to provide
* formatting services to their clients. The move to the
* start of the echo line, and the erase to the end of
* the echo line, is done by the caller.
* Note: %c works, and prints the "name" of the character.
* %k prints the name of a key (and takes no arguments).
*/
static VOID eformat(fp, ap)
register char *fp;
register va_list *ap;
{
register int c;
char kname[NKNAME];
char *cp;
refreshoffset = 0;
refreshmsg[0] = '\0';
collectPrompt = TRUE;
while ((c = *fp++) != '\0') {
if (c != (char)'%')
eputc((char)c);
else {
c = *fp++;
switch (c) {
case 'c':
(VOID) mykeyname(kname, va_arg(*ap, int));
eputs(kname);
break;
case 'k':
cp = kname;
for(c=0; c < key.k_count; c++) {
cp = mykeyname(cp, key.k_chars[c]);
*cp++ = ' ';
}
*--cp = '\0';
eputs(kname);
break;
case 'd':
eputi(va_arg(*ap, int), 10);
break;
case 'o':
eputi(va_arg(*ap, int), 8);
break;
case 's':
eputs(va_arg(*ap, char *));
break;
case 'l':/* explicit longword */
c = *fp++;
switch(c) {
case 'd':
eputl((long)va_arg(*ap, long), 10);
break;
default:
eputc((char)c);
break;
}
break;
default:
eputc((char)c);
}
}
}
collectPrompt = FALSE;
}
/*
* Put integer, in radix "r".
*/
static VOID eputi(i, r)
register int i;
register int r;
{
register int q;
if(i<0) {
eputc('-');
i = -i;
}
if ((q=i/r) != 0)
eputi(q, r);
eputc((char)(i%r+'0'));
}
/*
* Put long, in radix "r".
*/
static VOID eputl(l, r)
register long l;
register int r;
{
register long q;
if(l < 0) {
eputc('-');
l = -l;
}
if ((q=l/r) != 0)
eputl(q, r);
eputc((char)((l%r)+'0'));
}
/*
* Put string.
*/
static VOID eputs(s)
register char *s;
{
register char c;
while ((c = *s++) != '\0')
eputc(c);
ttflush(FALSE);
}
/*
* Put character. Watch for
* control characters, and for the line
* getting too long.
*/
static VOID eputc(c)
register char c;
{
if ((ttcol+2 < ncol) || ealtmsg)
{
if (ISCTRL(c))
{
eputc('^');
c = (char)CCHR(c);
}
if (ealtmsg)
{
altmsg[altoffset++] = c;
altmsg[altoffset] = 0;
}
else
{
ttputc(c);
++ttcol;
if (collectPrompt)
{
refreshmsg[refreshoffset++] = c;
refreshmsg[refreshoffset] = 0;
}
}
}
}
/* Alternative message dumping which will
* not mess up current status (for code running during timer
* callback, for example)
*/
static void altmessage(s)
char *s;
{
int curcolor;
int currow, curcol;
if (ttfatal())
return;
currow = ttrow;
curcol = ttcol;
curcolor = tthue;
ttcolor(EchoColor);
ttmove(nrow - 1, 0);
tteeol();
ttputline(s);
ttcolor(curcolor);
ttmove(currow, curcol);
ttflush(FALSE);
}
/* Deal with unexpected chars during echo-line stuff.
* (ughly!)
*
* Attempts to collect events from 'interrupting' commands
* to be re-entered into input stream later (main.c)
*/
BOOL handleKchar(c)
int c;
{
int s = c;
BOOL metakey = FALSE;
if (s == CCHR('['))
{
s = getkey(FALSE); /* grab the key and throw it away */
s |= METABIT;
metakey = TRUE;
}
switch (c)
{
case KEXTEND: /* silent_extended command */
PutbackKchar((KCHAR)c); /* put back trigger char... */
ttflushinput(FALSE); /* and any parameters..*/
c = 0;
break;
default:
break;
}
if (metakey)
{
PutbackKchar((KCHAR)s);
ttflushinput(FALSE);
}
return(c);
}
/* preload prompt screen
*/
void epreload(s)
char *s;
{
if (preload_)
strcpy(preload, s);
else
preload[0] = '\0';
enable_preload();
}
void erepair()
{
if (epresf || eprompting)
{
AddKchar(CCHR('Z'));
ttflush(FALSE);
}
}